Heap堆——数据结构系列教程(c++版)

梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)


  堆(Heap)是计算机科学中的一种特殊数据结构,堆的物理结构本质上是顺序存储的,是线性的。但在逻辑上不是线性的,是完全二叉树的这种逻辑储存结构。将根结点最大的堆叫做最大堆或大根堆,根结点最小的堆叫做最小堆或小根堆。核心优势是能快速获取极值(最大值 / 最小值)并维护堆性质,通常作为优先级队列、堆排序使用。堆在极值相关操作上具有压倒性优势,是算法设计和工程开发中不可或缺的数据结构。本教程基于动态数组实现的小根堆,从核心原理、代码结构到实战使用,全面讲解堆的原理与实现,功能包含入堆(向堆中插入元素)、出堆(删除并返回堆顶元素(极值))、向上堆化、向下堆化、堆排序等核心功能。

教程目录导航

一、堆的核心原理

1.1 堆的性质

  1. 堆中某个结点的值总是不大于或不小于其父结点的值;
  2. 堆总是一棵完全二叉树。

演示动画

1.2 核心优势

  1. 能快速获取极值(最大值 / 最小值)。
    • Top K :问题指从海量数据中找出前 K 个最大 / 最小元素(如 Top K 热门商品、Top K 高频词汇、Top K 高分学生等)。
    • 堆排序:高效排序算法,最坏 / 平均 / 最好时间复杂度一致,稳定性优于快速排序;。
    • 优先队列:队列中的元素按优先级排序,出队时总是优先级最高(或最低)的元素先出队。
    • 图(最短路径):用小根堆存储待处理节点及其到起点的距离,每次快速取出距离最小的节点(O (1)),并更新其邻接节点的距离(O (log n))。
  2. 入堆(向堆中插入元素)、出堆(删除并返回堆顶元素(极值))时间复杂度为O(log₂n)。注:包含维护堆性质。
  3. 小根堆切换大根堆,只需将堆化时与父节点的比较运算符修改成 >。

1.3 关键特征

  1. 父节点索引:p = (c-1)/2
  2. 左节点索引:c = 2p+1
  3. 右节点索引:c = 2p+2

1.4 堆化

堆化是维护堆的核心性质的核心操作,本质是将不符合堆性质的节点调整到正确位置。

分为「向上堆化(Heapify Up)」和「向下堆化(Heapify Down)」两种,二者是堆的插入、删除、构建等操作的基础。

(1)向上堆化(Heapify Up)

插入元素后:新元素被添加到堆的末尾(数组最后一位),可能破坏堆的性质(比如最小堆中,子节点 < 父节点),需要从该节点向上「爬升」,直到找到符合堆性质的位置。

(1)向下堆化(Heapify Down)

删除堆顶元素后:将堆的最后一个元素移到堆顶(填补空缺),可能破坏堆的性质(比如最小堆中,父节点 > 子节点),需要从堆顶向下「下沉」,直到找到符合堆性质的位置。

二、代码结构解析

2.1 整体架构

提供的代码是模板化的堆实现(支持任意类型),采用C++结构体封装,分为头文件(声明)和源文件(实现)两部分,核心结构如下:

模块 作用 关键结构/函数
堆结构体 封装所有操作 ArrayHeap<T>(模板类)

2.2 关键结构体详解

(1)堆结构体(ArrayHeap)


template <typename T, typename Compare = std::less<T>>
struct ArrayHeap{
    // ------------------------------------------------------------------------------------------------------
    //                                          私有成员
    // 注:私有成员只能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)不能访问调用)
    //------------------------------------------------------------------------------------------------------
    private:

        //---------------声明私有成员变量---------------

        std::vector<T> heap;  // 模板化堆元素,支持存储任意类型

        //---------------声明私有成员函数---------------

        int parent(int index);      // 获取父节点索引
        int leftChild(int index);   // 获取左子节点索引
        int rightChild(int index);  // 获取右子节点索引
        void swap(int i, int j);   // 交换两个元素
        void heapifyUp(int index);  // 向上堆化:维护最小堆性质(插入元素后调用)
        void heapifyDown(int index);// 向下堆化:维护最小堆性质(删除堆顶后调用)
        void buildHeap(std::vector<T>& arr);           // 批量构建堆的向下堆化

    // ------------------------------------------------------------------------------------------------------
    //                                          公共成员
    // 注:公共成员能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)也能访问调用)
    //------------------------------------------------------------------------------------------------------
    public:

        //---------------声明公共成员函数---------------

        // 构造函数:外部通过该结构体定义(实例化)变量(对象)时,自动执行该函数(主要用于初始化成员变量的值)
        ArrayHeap() {
        }

        // 用数组构建堆
        ArrayHeap(std::vector<T>& arr) {
            buildHeap(arr);             //批量构建堆的向下堆化
        }

        void insert(const T& value);    // 插入元素到堆中
        std::vector<T> sort(int type); // 排序
        T extractMin();                  // 删除并返回堆顶元素(最小值)
        T getMin();                      // 获取堆顶元素(最小值,不删除)
        int size();                     // 获取堆的大小
        bool isEmpty();                 // 判断堆是否为空
        void print();                   // 打印堆数据

        // 析构函数:自动销毁队列,避免内存泄漏
        ~ArrayHeap() {
        }
};

三、核心操作实现详解

3.1 获取节点索引

获取父节点、左右子节点索引是堆能够高效实现核心操作的基础,直接通过算术运算即可得到节点位置。

(1)获取父节点索引(parent)

p = ( index - 1 ) / 2,index为子节点索引

template <typename T, typename Compare>
int ArrayHeap<T,Compare>::parent(int index) {
    return (index - 1) / 2;
}

(2)获取左子节索引(leftChild)

c = 2 index + 1,p为父节点索引

template <typename T, typename Compare>
int ArrayHeap<T,Compare>::leftChild(int index) {
    return 2 * index + 1;
}

(3)获取右子节索引(rightChild)

c = 2 index + 2,p为父节点索引

template <typename T, typename Compare>
int ArrayHeap<T,Compare>::rightChild(int index) {
    return 2 * index + 2;
}

3.2 入堆(put)

入推流程:

  1. 将元素添加到数组末尾;
  2. 向上堆化最后一个元素;
template <typename T, typename Compare>
void ArrayHeap<T,Compare>::put(const T& value) {
    heap.push_back(value);  // 元素添加到数组末尾
    heapifyUp(heap.size() - 1);  // 向上堆化最后一个元素
}
向上堆化(辅助函数)
template <typename T, typename Compare>
void ArrayHeap<T,Compare>::heapifyUp(int index) {
    // 非根节点,且当前节点 < 父节点 → 交换并继续向上调整
    //if (index > 0 && heap[index] < heap[parent(index)]) {
    if(index > 0 && cmp(heap[index], heap[parent(index)])) {
        swap(index, parent(index));
        heapifyUp(parent(index));  // 递归调整父节点
    }
}
交换两个元素(辅助函数)
template <typename T, typename Compare>
void ArrayHeap<T,Compare>::swap(int i, int j) {
    T temp = heap[i];
    heap[i] = heap[j];
    heap[j] = temp;
}

3.3 出堆(get)

出堆流程:

  1. 取出堆顶元素
  2. 将最后一个元素移到堆顶,然后删除最后一个元素;
  3. 向下堆化堆顶元素;
template <typename T, typename Compare>
T ArrayHeap<T,Compare>::get() {
    if (isEmpty()) {
        throw std::runtime_error("Error: 无法从空堆中删除元素!");
    }

    T minValue = heap[0];  // 保存堆顶最小值
    // 堆只有一个元素时,直接弹出
    if (heap.size() == 1) {
        heap.pop_back();
        return minValue;
    }

    // 最后一个元素移到堆顶,然后删除最后一个元素
    heap[0] = heap.back();
    heap.pop_back();
    heapifyDown(0);  // 向下堆化堆顶元素

    return minValue;
}

向下堆化(辅助函数)

template <typename T, typename Compare>
void ArrayHeap<T,Compare>::heapifyDown(int index) {
    int smallest = index;  // 初始化最小值索引为当前节点
    int left = leftChild(index);
    int right = rightChild(index);

    // 左子节点存在且更小 → 更新最小值索引
    //if (left < heap.size() && heap[left] < heap[smallest]) {
    if (left < heap.size() && cmp(heap[left],heap[smallest])) {
        smallest = left;
    }

    // 右子节点存在且更小 → 更新最小值索引
    //if (right < heap.size() && heap[right] < heap[smallest]) {
    if (right < heap.size() && cmp(heap[right],heap[smallest])) {
        smallest = right;
    }

    // 最小值不是当前节点 → 交换并递归调整子节点
    if (smallest != index) {
        swap(index, smallest);
        heapifyDown(smallest);
    }
}

3.4 批量构建堆

出堆流程:

  1. 初始化时传入动态数组引用;注:在定义或实例化变量和对象时传入。
  2. 批量构建堆的向下堆化;
template <typename T, typename Compare>
ArrayHeap(std::vector<T,Compare>& arr) {
    buildHeap(arr);             //批量构建堆的向下堆化
}

批量向下堆化(辅助函数)

template <typename T, typename Compare>
void ArrayHeap<T,Compare>::buildHeap(std::vector& arr) {
    heap = arr;
    int startIdx = (heap.size() - 2) / 2;  // 最后一个非叶子节点
    for (int i = startIdx; i >= 0; --i) {
        heapifyDown(i); // 从下向上批量堆化
    }
}

3.5 堆排序

不破坏原堆数据,形参type: 0 为升序 1 为降序

template <typename T, typename Compare>
std::vector<T,Compare> ArrayHeap<T>::sort(int type) {
    if (isEmpty()) {
        return {};
    }

    ArrayHeap tempHeap(heap);// 复制当前堆,避免破坏原堆结构
    std::vector<T> sortedArr;

    // 依次提取最小值,生成升序数组
    while (!tempHeap.isEmpty()) {
        sortedArr.push_back(tempHeap.get());
    }

    //降序
    if(type == 1)
    {
        reverse(sortedArr.begin(),sortedArr.end());	//进行反转
    }

    return sortedArr;
}

四、实战使用示例

4.1 基础类型(int)使用示例

#include "ArrayHeap.h"
#include <iostream>

int main() {   

    // 1. 插入'f','e','c','d','b','j','g','h','i','a'
    vector<char> arrayChar = {'f','e','c','d','b','j','g','h','i','a'};
    ArrayHeap<char> hape(arrayChar);//批量堆化
    hape.print();

    // 2. 排序
    vector<char> arrayAsc = hape.sort();
    cout << "升序排序: ";
    for(int i=0;i < arrayAsc.size();i++)
    {
        cout << arrayAsc[i] << " ";
    }
    cout << endl;

    // 3. 入堆 k
    cout << "入堆元素 : k" << endl;
    hape.put('k');
    hape.print();
    vector<char> arrayDesc = hape.sort();
    cout << "降序排序: ";
    for(int i=arrayDesc.size()-1;i>=0;i--)
    {
        cout << arrayDesc[i] << " ";
    }
    cout << endl;
    
    return 0;
}

输出结果


小根堆元素: a b c d e j g h i f
升序排序: a b c d e f g h i j
入堆元素 : k
小根堆元素: a b c d e j g h i f k
降序排序: k j i h g f e d c b a
            

4.2 自定义类型(Student)使用示例

需先定义Student结构体,并重载比较运算符(<==><<):

ArrayHeap.cpp中显式实例化常用类型(避免链接错误)

// Student类定义(Entitys.h)
#include <string>
struct Student {
    int id;
    std::string name;

    // 重载==:用于查找/删除
    bool operator==(const Student& other) const {
        return id == other.id;
    }

    // 重载<:用于比较
    bool operator<(const Student& other) const {
        return id < other.id;
    }

    // 重载>:用于比较
    bool operator>(const Student& other) const {
        return id > other.id;
    }

    // 重载<<:用于输出
    friend std::ostream& operator<<(std::ostream& os, const Student& s) {
        os << "ID: " << s.id << ", Name: " << s.name;
        return os;
    }
};

// 使用示例
#include "ArrayHeap.h"
#include <iostream>
int main() {
    ArrayHeap<Student> studentHeap;

    // 1. 入堆学生节点
    studentHeap.put({101, "张三"});
    studentHeap.put({102, "李四"});
    studentHeap.put({100, "王五"});
    studentHeap.print();

    // 2. 排序
    vector<Student> studentTemp = studentHeap.sort();
    cout << "升序排序: ";
    for (Student num : studentTemp) {
        cout << num.id << " " << num.name<< " " ;
    }
    cout << endl;

    return 0;
}

输出结果


小根堆元素: [100, 王五, 0 ] [102, 李四 0 ] [101, 张三 0 ]
升序排序: 100 王五 101 张三 102 李四
            

五、完整可运行代码

5.1 Entitys.h 头文件


#ifndef ENTITYS_H_INCLUDED
#define ENTITYS_H_INCLUDED

//************************************************************************************************************************************************************************
//                                                                      自定义类型
//************************************************************************************************************************************************************************

//========================================================================================================================================================================
//                                                                    学生结构体(Student)
//========================================================================================================================================================================
struct Student {
    int id;// 学号
    std::string name;// 姓名
    std::string dob;// 出生日期
    std::string sex;// 性别
    std::string gender;// 民族
    std::string address;// 地址
    float score;// 入学总分
    std::string school;// 学校
    std::string team;// 班级
    std::string status;// 状态

    bool operator<(const Student& other) const { return id < other.id; }
    bool operator>(const Student& other) const { return id > other.id; }
    bool operator==(const Student& other) const { return id == other.id; }
    bool operator!=(const Student& other) const { return id != other.id; }

    friend std::ostream& operator<<(std::ostream& os, const Student& s) {
        os << "[" << s.id<< ", " << s.name << ", " << s.dob << ", " << s.sex << ", " << s.gender  << ", " << s.address << ", " << s.score<< ", " << s.school<< ", " << s.team<< ", " << s.status << "]";
        return os;
    }
};

//========================================================================================================================================================================
//
//                                                                    学生索引结构体(Student)
//
//========================================================================================================================================================================
struct StudentIndex {
    int id;// 学号
    int row;// 行号

    bool operator<(const StudentIndex& other) const { return id < other.id; }
    bool operator>(const StudentIndex& other) const { return id > other.id; }
    bool operator==(const StudentIndex& other) const { return id == other.id; }
    bool operator!=(const StudentIndex& other) const { return id != other.id; }

    friend std::ostream& operator<<(std::ostream& os, const StudentIndex& i) {
        os << "[" << i.id << ", " << i.row<< "]";
        return os;
    }
};

//========================================================================================================================================================================
//                                                                    迷宫坐标结构体(Pos)
//========================================================================================================================================================================
struct Pos{
    int x;     //x坐标
    int y;    //y坐标
    int step; //步数
};

//========================================================================================================================================================================
//                                                                    打印任务结构体(PrintTask)
//========================================================================================================================================================================
struct PrintTask{
    int taskId;     // 任务ID
    char content[50]; // 打印内容
};

//========================================================================================================================================================================
//
//                                                                    哈夫曼树节点结构体(HuffmanNode)
//
//========================================================================================================================================================================
struct HuffmanNode {
    char ch;                // 字符(非叶子节点设为 '\0')
    int freq;               // 频率
    HuffmanNode *left;      // 左子节点
    HuffmanNode *right;     // 右子节点

    bool operator<(const HuffmanNode& other) const { return freq < other.freq; }
    bool operator>(const HuffmanNode& other) const { return freq > other.freq; }
    bool operator==(const HuffmanNode& other) const { return freq == other.freq; }
    bool operator!=(const HuffmanNode& other) const { return freq != other.freq; }

    friend std::ostream& operator<<(std::ostream& os, const HuffmanNode* h) {
        os << "[" << h->ch << ", " << h->freq<< "]";
        return os;
    }
};

//========================================================================================================================================================================
//
//                                                                    使用指针类型时,传入自定义比较器
//
//========================================================================================================================================================================
struct HuffmanNodeCmp {
    bool operator()(HuffmanNode* a, HuffmanNode* b) {
        return a->freq < b->freq; // 比较节点权重
    }
};

//========================================================================================================================================================================
//
//                                                                    哈夫曼编码表结构体(CodeTable)
//
//========================================================================================================================================================================
struct CodeTable {
    char ch;
    char code[MAX_CODE_LEN];
};
            
            #endif // ENTITYS_H_INCLUDED
                    

5.2 ArrayHeap.h 头文件


#ifndef LINKEDBSTREE_H_INCLUDED
#define LINKEDBSTREE_H_INCLUDED

#include <iostream>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include "Entitys.h"

//========================================================================================================================================================================
//
//                                                                 数组堆结构体(ArrayHeap)
//
//========================================================================================================================================================================
template <typename T, typename Compare = std::less<T>>
struct ArrayHeap{
    // ------------------------------------------------------------------------------------------------------
    //                                          私有成员
    // 注:私有成员只能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)不能访问调用)
    //------------------------------------------------------------------------------------------------------
    private:

        //---------------声明私有成员变量---------------

        std::vector<T> heap;  // 模板化堆元素,支持存储任意类型

        //---------------声明私有成员函数---------------

        int parent(int index);      // 获取父节点索引
        int leftChild(int index);   // 获取左子节点索引
        int rightChild(int index);  // 获取右子节点索引
        void swap(int i, int j);   // 交换两个元素
        void heapifyUp(int index);  // 向上堆化:维护最小堆性质(插入元素后调用)
        void heapifyDown(int index);// 向下堆化:维护最小堆性质(删除堆顶后调用)
        void buildHeap(std::vector<T>& arr);           // 批量构建堆的向下堆化

    // ------------------------------------------------------------------------------------------------------
    //                                          公共成员
    // 注:公共成员能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)也能访问调用)
    //------------------------------------------------------------------------------------------------------
    public:

        //---------------声明公共成员函数---------------

        // 构造函数:外部通过该结构体定义(实例化)变量(对象)时,自动执行该函数(主要用于初始化成员变量的值)
        ArrayHeap() {
        }

        // 用数组构建堆
        ArrayHeap(std::vector<T>& arr) {
            buildHeap(arr);             //批量构建堆的向下堆化
        }

        void put(const T& value);       // 入堆,插入元素到堆中
        std::vector<T> sort(int type); // 排序
        T get();                         // 出堆,删除并返回堆顶元素(最小值)
        T getMin();                      // 获取堆顶元素(最小值,不删除)
        int size();                     // 获取堆的大小
        bool isEmpty();                 // 判断堆是否为空
        void print();                   // 打印堆数据

        // 析构函数:自动销毁队列,避免内存泄漏
        ~ArrayHeap() {
        }
};

#endif // ARRAYHEAP_H_INCLUDED

5.3 ArrayHeap.cpp 程序代码


#include "ArrayHeap.h"
//---------------实现私有成员函数---------------

// 获取父节点索引
template <typename T, typename Compare>
int ArrayHeap<T,Compare>::parent(int index) {
    return (index - 1) / 2;
}

// 获取左子节点索引
template <typename T, typename Compare>
int ArrayHeap<T,Compare>::leftChild(int index) {
    return 2 * index + 1;
}

// 获取右子节点索引
template <typename T, typename Compare>
int ArrayHeap<T,Compare>::rightChild(int index) {
    return 2 * index + 2;
}

// 交换两个元素
template <typename T, typename Compare>
void ArrayHeap<T,Compare>::swap(int i, int j) {
    T temp = heap[i];
    heap[i] = heap[j];
    heap[j] = temp;
}

// 向上堆化:维护最小堆性质(插入元素后调用
template <typename T, typename Compare>
void ArrayHeap<T,Compare>::heapifyUp(int index) {
    // 非根节点,且当前节点 < 父节点 → 交换并继续向上调整
    //if (index > 0 && heap[index] < heap[parent(index)]) {
    if(index > 0 && cmp(heap[index], heap[parent(index)])) {
        swap(index, parent(index));
        heapifyUp(parent(index));  // 递归调整父节点
    }
}

// 向下堆化:维护最小堆性质(删除堆顶后调用)
template <typename T, typename Compare>
void ArrayHeap<T,Compare>::heapifyDown(int index) {
    int smallest = index;  // 初始化最小值索引为当前节点
    int left = leftChild(index);
    int right = rightChild(index);

    // 左子节点存在且更小 → 更新最小值索引
    //if (left < heap.size() && heap[left] < heap[smallest]) {
    if (left < heap.size() && cmp(heap[left],heap[smallest])) {
        smallest = left;
    }

    // 右子节点存在且更小 → 更新最小值索引
    //if (right < heap.size() && heap[right] < heap[smallest]) {
    if (right < heap.size() && cmp(heap[right],heap[smallest])) {
        smallest = right;
    }

    // 最小值不是当前节点 → 交换并递归调整子节点
    if (smallest != index) {
        swap(index, smallest);
        heapifyDown(smallest);
    }
}

//批量构建堆的向下堆化
template <typename T, typename Compare>
void ArrayHeap<T,Compare>::buildHeap(std::vector<T>& arr) {
    heap = arr;
    int startIdx = (heap.size() - 2) / 2;  // 最后一个非叶子节点
    for (int i = startIdx; i >= 0; --i) {
        heapifyDown(i); // 从下向上批量堆化
    }
}

//---------------实现公共成员函数---------------

// 入堆,插入元素到堆中
template <typename T, typename Compare>
void ArrayHeap<T,Compare>::put(const T& value) {
    heap.push_back(value);  // 元素添加到数组末尾
    heapifyUp(heap.size() - 1);  // 向上堆化最后一个元素
}

// 基于当前堆的元素,返回升序排序结果(不破坏原堆) 0 为升序 1 为降序
template <typename T, typename Compare>
std::vector<T> ArrayHeap<T,Compare>::sort(int type) {
    if (isEmpty()) {
        return {};
    }

    ArrayHeap tempHeap(heap);// 复制当前堆,避免破坏原堆结构
    std::vector<T> sortedArr;

    // 依次提取最小值,生成升序数组
    while (!tempHeap.isEmpty()) {
        sortedArr.push_back(tempHeap.get());
    }

    //降序
    if(type == 1)
    {
        reverse(sortedArr.begin(),sortedArr.end());	//进行反转
    }

    return sortedArr;
}

// 出堆,删除并返回堆顶元素(最小值)
template <typename T, typename Compare>
T ArrayHeap<T,Compare>::get() {
    if (isEmpty()) {
        throw std::runtime_error("Error: 无法从空堆中删除元素!");
    }

    T minValue = heap[0];  // 保存堆顶最小值
    // 堆只有一个元素时,直接弹出
    if (heap.size() == 1) {
        heap.pop_back();
        return minValue;
    }

    // 最后一个元素移到堆顶,然后删除最后一个元素
    heap[0] = heap.back();
    heap.pop_back();
    heapifyDown(0);  // 向下堆化堆顶元素

    return minValue;
}

// 获取堆顶元素(最小值,不删除)
template <typename T, typename Compare>
T ArrayHeap<T,Compare>::getMin() {
    if (isEmpty()) {
        throw std::runtime_error("Error: 堆为空,无堆顶元素!");
    }
    return heap[0];
}

// 获取堆的大小
template <typename T, typename Compare>
int ArrayHeap<T,Compare>::size() {
    return heap.size();
}

// 判断堆是否为空
template <typename T, typename Compare>
bool ArrayHeap<T,Compare>::isEmpty() {
    return heap.empty();
}

// 打印堆的所有元素
template <typename T, typename Compare>
void ArrayHeap<T,Compare>::print() {
    std::cout << "小根堆元素: ";
    for (T num : heap) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
}

// 显式实例化常用类型(避免链接错误,可选)
template class ArrayHeap<int>;
template class ArrayHeap<char>;
template class ArrayHeap<float>;
template class ArrayHeap<std::string>;
template class ArrayHeap<Student>;
template class ArrayHeap<HuffmanNode*>; 
template class ArrayHeap<HuffmanNode*, HuffmanNodeCmp>;

5.4 main.cpp 测试代码


#include <iostream>
#include <string>
#include "ArrayHeap.h"

int main() {   

    // 1. 插入'f','e','c','d','b','j','g','h','i','a'
    vector<char> arrayChar = {'f','e','c','d','b','j','g','h','i','a'};
    ArrayHeap<char> hape(arrayChar);//批量堆化
    hape.print();

    // 2. 排序
    vector<char> arrayAsc = hape.sort();
    cout << "升序排序: ";
    for(int i=0;i < arrayAsc.size();i++)
    {
        cout << arrayAsc[i] << " ";
    }
    cout << endl;

    // 3. 入堆 k
    cout << "入堆元素 : k" << endl;
    hape.put('k');
    hape.print();
    vector<char> arrayDesc = hape.sort();
    cout << "降序排序: ";
    for(int i=arrayDesc.size()-1;i>=0;i--)
    {
        cout << arrayDesc[i] << " ";
    }
    cout << endl;
    
    return 0;
}

输出结果


小根堆元素: a b c d e j g h i f
升序排序: a b c d e f g h i j
入堆元素 : k
小根堆元素: a b c d e j g h i f k
降序排序: k j i h g f e d c b a
    

六、注意事项

模板类型约束

  • 模板类型需支持</>/==运算符(内置类型如int/string默认支持,自定义类型需重载);
  • 自定义类型需重载<<运算符(打印输出时使用)。

显式实例化:代码末尾的template class ArrayHeap<int>;等显式实例化,避免链接错误,新增类型需补充显式实例化。

七、总结

堆是一种高效的优先队列实现,核心是利用完全二叉树的结构特性,通过向上堆化向下堆化操作维护堆序性。其核心价值在于快速获取最值,在 Top-K、优先队列、多路归并等场景中不可或缺。

常见坑点与避坑经验

本教程通过代码解析和实战示例,覆盖了堆的核心原理、关键操作实现和实际使用场景。掌握堆的原理和实现,区分不同场景下的堆类型选择,并通过实战(如手写堆、解决 Top-K 问题)加深理解。


返回顶部